package com.xrf;

import java.text.MessageFormat;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.system.as.application.common.CodeBusiness;
import com.system.as.application.system.basics.business.entity.BusinessSeqEntity;
import com.system.as.application.system.basics.business.mapper.BusinessSeqMapper;
import com.system.as.application.system.common.CodeBusinessSystem;
import com.system.core.common.base.SystemServiceImpl;
import com.system.core.tool.ToolMath;
import com.system.core.tool.ToolRedis;
import com.system.core.tool.ToolTime;

@Service
public class BusinessSeqService extends SystemServiceImpl<BusinessSeqMapper, BusinessSeqEntity> {
    private static Logger logger = LoggerFactory.getLogger(BusinessSeqService.class);
    
    @Autowired
    private BusinessInfoService businessInfoService;
    
    @Autowired
    private ToolRedis toolRedis;
    
    @Transactional
    public boolean insert(String bsKey, String bsSeq, String beforeTip, String afterTip, String isUse) {
        return insert(bsKey, bsSeq, beforeTip, afterTip, null, isUse);
    }
    
    @Transactional
    public boolean insert(String bsKey, String bsSeq, String beforeTip, String afterTip, String lastValue, String isUse) {
        if (businessInfoService.isExit(bsKey)) {
            return false;
        }
        BusinessSeqEntity entity = new BusinessSeqEntity();
        entity.setBsKey(bsKey);
        entity.setBsSeq(bsSeq);
        entity.setBeforeTip(beforeTip);
        entity.setAfterTip(afterTip);
        entity.setIsUse(isUse);
        entity.setLastValue(lastValue);
        entity.setLastDate(ToolTime.getNowDate());
        logger.info("准备新增考勤业务编码，参数：entity={}", entity);
        boolean result = save(entity);
        logger.info("新增考勤业务编码结束，结果：{}", result);
        return result;
    }
    
    public BusinessSeqEntity selectEntity(String bsKey, String bsSeq) {
        if (StringUtils.isBlank(bsSeq) || StringUtils.isBlank(bsKey)) {
            return null;
        }
        String key = MessageFormat.format(CodeBusinessSystem.REDIS_SYS_BUSINESS_KEY.getValue(), bsKey, bsSeq);
        BusinessSeqEntity cacheEntity = (BusinessSeqEntity) toolRedis.get(key);
        if (null != cacheEntity) {
            return cacheEntity;
        }
        QueryWrapper<BusinessSeqEntity> queryWrapper = new QueryWrapper<BusinessSeqEntity>();
        queryWrapper.eq("BS_KEY", bsKey);
        queryWrapper.eq("BS_SEQ", bsSeq);
        cacheEntity = getOne(queryWrapper);
        if (null == cacheEntity) {
            cacheEntity = new BusinessSeqEntity();
            cacheEntity.setAfterTip("");
            cacheEntity.setBeforeTip("");
            cacheEntity.setBsKey(bsKey);
            cacheEntity.setBsSeq(bsSeq);
            cacheEntity.setLastValue("00000001");
            cacheEntity.setIsUse(CodeBusiness.IS_USE.Y.name());
            cacheEntity.setLastDate(ToolTime.getNowDate());
            save(cacheEntity);
        }
        if (cacheEntity != null) {
            toolRedis.set(key, cacheEntity);
        }
        return cacheEntity;
    }
    
    @Transactional
    public BusinessSeqEntity update(BusinessSeqEntity entity) {
        String key = MessageFormat.format(CodeBusinessSystem.REDIS_SYS_BUSINESS_KEY.getValue(), entity.getBsKey(),
                entity.getBsSeq());
        QueryWrapper<BusinessSeqEntity> queryWrapper = new QueryWrapper<BusinessSeqEntity>();
        queryWrapper.eq("BS_KEY", entity.getBsKey());
        queryWrapper.eq("BS_SEQ", entity.getBsSeq());
        update(entity, queryWrapper);
        toolRedis.set(key, entity);
        return entity;
    }
    
    public String[] nextValuePlus(String type, String key, Integer length) {
        String[] resultValues = null;
        if (null == length) {
            resultValues = new String[1];
            resultValues[0] = nextValuePlus(type, key);
        } else {
            resultValues = new String[length.intValue()];
            for (int i = 0, j = resultValues.length; i < j; i++) {
                resultValues[i] = nextValuePlus(type, key);
            }
        }
        return resultValues;
    }
    
    public String nextValuePlus(String type, String key) {
        String nextKey = MessageFormat.format(CodeBusinessSystem.REDIS_SYS_BUSINESS_PLUS_KEY.getValue(), type, key);
        String maxKey = MessageFormat.format(CodeBusinessSystem.REDIS_SYS_BUSINESS_PLUS_MAX_KEY.getValue(), type, key);
        Long maxValue = null;
        Object max = toolRedis.get(maxKey);
        Long nextValue = toolRedis.getAutoIncrement(nextKey);
        if (null == max && nextValue == 1) {
            BusinessSeqEntity entity = selectEntity(type, key);
            nextValue = Long.parseLong(entity.getLastValue());
            maxValue = nextValue + CodeBusinessSystem.PLUS_KEY_LENGTH;
            toolRedis.set(nextKey, nextValue);
            toolRedis.setKeyValueIsNotExists(maxKey, maxValue);
            entity.setLastValue(ToolMath.getResult(maxValue, 8));
            update(entity);
            return nextValuePlus(type, key);
        } else if (null == max && nextValue != 1) {
            waitMax(maxKey, nextValue, type, key);
            return nextValuePlus(type, key);
        } else {
            maxValue = ((Integer) max).longValue();
            if (maxValue > nextValue) {
                BusinessSeqEntity entity = selectEntity(type, key);
                String _nextValue = ToolMath.getResult(nextValue, 8);
                return (StringUtils.isBlank(entity.getBeforeTip()) ? "" : entity.getBeforeTip()) + _nextValue
                        + (StringUtils.isBlank(entity.getAfterTip()) ? "" : entity.getAfterTip());
            } else if (maxValue.longValue() == nextValue.longValue()) {
                toolRedis.delKey(maxKey);
                BusinessSeqEntity entity = selectEntity(type, key);
                nextValue = Long.parseLong(entity.getLastValue());
                maxValue = nextValue + CodeBusinessSystem.PLUS_KEY_LENGTH;
                toolRedis.setKeyValueIsNotExists(maxKey, maxValue);
                entity.setLastValue(ToolMath.getResult(maxValue, 8));
                update(entity);
                return nextValuePlus(type, key);
            } else {
                waitMax(maxKey, nextValue, type, key);
                return nextValuePlus(type, key);
            }
        }
    }
    
    private boolean waitMax(String maxKey, long i, String type, String key) {
        try {
            Object max = toolRedis.get(maxKey);
            if (null == max) {
                Thread.sleep(500);
                if (i == 1) {
                    String nextKey = MessageFormat.format(CodeBusinessSystem.REDIS_SYS_BUSINESS_PLUS_KEY.getValue(),
                            type, key);
                    BusinessSeqEntity entity = selectEntity(type, key);
                    Long nextValue = Long.parseLong(entity.getLastValue());
                    Long maxValue = nextValue + CodeBusinessSystem.PLUS_KEY_LENGTH;
                    toolRedis.setKeyValueIsNotExists(nextKey, nextValue);
                    toolRedis.setKeyValueIsNotExists(maxKey, maxValue);
                    entity.setLastValue(ToolMath.getResult(maxValue, 8));
                    update(entity);
                    return true;
                }
                waitMax(maxKey, i - 1, type, key);
            }
        } catch (InterruptedException e) {
            logger.error("等待设置Max值出现异常", e);
        }
        return true;
    }
}